/*
 * IConnection.cpp
 *
 *  Created on: 09.08.2011
 *      Author: Blinov Kirill
 *   Copyright: LGPL
 *
 */

#include "IConnection.h"

CConnectionLogic::CConnectionLogic( UINT ConnectionId,
									boost::function<bool( const UINT, UINT64 )> ConnectionStatusCallback,
									boost::asio::ip::tcp::endpoint *Endpoint,
									boost::asio::io_service        *Io_service,
									 TThreadSafeQueue<STANDART_NETWORK_MESSAGE*>* IncomeQueue ) :
	RReadWriteImplementation( ConnectionId, ConnectionStatusCallback, Endpoint, Io_service, IncomeQueue )
{
	connectionSocket = new boost::asio::ip::tcp::socket( *io_service );
}

CConnectionLogic::~CConnectionLogic()
{
	//Disconnect( false );
	delete connectionSocket;

	delete outputQueue;

	if ( IncomeMessage != NULL )
	{
		delete IncomeMessage;
	}

	if ( DataArray != NULL )
	{
		delete DataArray;
		DataArray = NULL;
	}
	// ~RReadWriteImplementation()
}

/*
 *
 */

bool
CConnectionLogic::SendMessage( STANDART_NETWORK_MESSAGE* Message )
{
	return outputQueue->Send( Message );
}

void
CConnectionLogic::Disconnect( const bool SendMessage = false )
{
	fprintf( stderr, "[CONNECTION] %u CConnectionLogic::Disconnect() %u - %p\n", connectionId, ConnectionEstabilished, outputQueue );
	if ( ConnectionEstabilished )
	{
		ReadWriteAllow = false;
		syncWritingThread.join(); //Waiting for writing thread finished
		if ( SendMessage )
		{
			STANDART_NETWORK_MESSAGE message( NETWORK_PROTOCOL_VERSION, NET_MESSAGE_GROUP_ACTION,
											  NET_MESSAGE_ACTION_REJECTION, connectionId );
			message.header.additionalData1 = NET_MESSAGE_ADD_CONNECTION_BREAK;

			connectionSocket->send( boost::asio::buffer( &message.header, sizeof(NETWORK_MESSAGE_HEADER) ));
		}

		boost::system::error_code ignored_ec;
		connectionSocket->shutdown( boost::asio::ip::tcp::socket::shutdown_both, ignored_ec );
		if ( ignored_ec )
		{
			fprintf( stderr, "[CONNECTION] CConnectionLogic::Disconnect() %u - Shutdown Failed\n", connectionId );
		}
		connectionSocket->close();
		ConnectionEstabilished = false;
		connectionErrorCallback( connectionId, ERROR_NETWORK_UNKNOWN_ERROR );
		// TODO Закрыть пайпы, дождаться тредов
	}
}

/*
 *
 */
CServerConnection::CServerConnection( UINT ConnectionId,
                                      boost::function<bool( const UINT, UINT64 )> ConnectionStatusCallback,
                                      boost::asio::ip::tcp::acceptor *Acceptor,
                                      boost::asio::ip::tcp::endpoint *Endpoint,
                                      boost::asio::io_service        *Io_service,
                                      TThreadSafeQueue<STANDART_NETWORK_MESSAGE*>* IncomeQueue ) :
     CConnectionLogic( ConnectionId, ConnectionStatusCallback, Endpoint, Io_service, IncomeQueue ),
     acceptor( Acceptor )
{

}

CServerConnection::~CServerConnection()
{
	//~CConnectionLogic()
}

void
CServerConnection::Start()
{
	fprintf( stderr, "[CONNECTION] CServerConnection::Start() %u - %p\n", ConnectionEstabilished, outputQueue );
	if ( !ConnectionEstabilished )
	{
		if ( DataArray != NULL )
		{
			delete DataArray;
			DataArray = NULL;
		}
		try
		{
			acceptor->async_accept( *connectionSocket, boost::bind( &CServerConnection::ConnectionHandler, this,
					                                                boost::asio::placeholders::error ) );
		}
		catch( std::exception& e )
		{
			fprintf( stderr, "[CRASH] !! CServerConnection::Start() Failed - %p\n", outputQueue  );
			connectionErrorCallback( connectionId, ERROR_NETWORK_ACCESS_DENIED );
			// TODO Добавить обработку исключений
		}
	}
}

/*
 * CClientConnection::CClientConnection
 */
CClientConnection::CClientConnection( UINT ConnectionId,
									  boost::function<bool( const UINT, UINT64 )> ConnectionStatusCallback,
									  boost::asio::ip::tcp::endpoint *Endpoint,
									  boost::asio::io_service        *Io_service,
									  TThreadSafeQueue<STANDART_NETWORK_MESSAGE*>* IncomeQueue ) :
	CConnectionLogic( ConnectionId, ConnectionStatusCallback, Endpoint, Io_service, IncomeQueue )
{

}

CClientConnection::~CClientConnection()
{
	//~CConnectionLogic()
}

void
CClientConnection::Start()// TODO Дублирование кода
{
	fprintf( stderr, "[CONNECTION] CClientConnection::Start() %u - %p\n", ConnectionEstabilished, outputQueue );
	if ( !ConnectionEstabilished )
	{
		if ( DataArray != NULL )
		{
			delete DataArray;
			DataArray = NULL;
		}
		try
		{
			connectionSocket->async_connect( *endpoint, boost::bind( &CClientConnection::ConnectionHandler, this,
																	  boost::asio::placeholders::error ) );
		}
		catch( std::exception& e )
		{
			fprintf( stderr, "[CRASH] CClientConnection::Start() Failed - %p\n", outputQueue  );
			connectionErrorCallback( connectionId, ERROR_NETWORK_ACCESS_DENIED );

		}
	}
}


